package com.atguigu.gmall.rebbit.config;


import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.rebbit.constant.RedisConst;
import com.atguigu.gmall.rebbit.entity.GmallCorrelationData;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import springfox.documentation.spring.web.json.Json;

import javax.annotation.PostConstruct;

//自定义应答实现类 rabbitTemplate发送的消息队列
//接收交换机应答
//接收队列的应答
//RabbitTemplate.ConfirmCallback 实现rabbitmq中的应答接口交换机及之前出错设置  RabbitTemplate.ReturnCallback实现rabbitmq的队列应答接口
@Component  //SpringIOC容器中
public class MQProducerAckConfig implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;
    @PostConstruct//构造器执行 就执行init注解方法
    public void init() {
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
    }

    //交换机应答 不管成功失败都需要应答
    @Override //ack 应答结果   true成功 false失败  cause描述原因，成功时为null correlationData为请求
    public void confirm(CorrelationData correlationData, boolean b, java.lang.String s) {
        GmallCorrelationData correlationData1= (GmallCorrelationData) correlationData;
        //判断是否为插件延迟消息
        if(correlationData1.getIsDelay()){
            return;
        }
        if(b){
        System.out.println("这里是重新发送");
    }else {
        System.out.println("失败应答：原因时"+s);
        //返回失败重新发送消息
        //封装方法
       retrySendMessage(correlationData);
    }

    }

    //重发封装
    private void retrySendMessage(CorrelationData correlationData) {
        GmallCorrelationData correlationData1= (GmallCorrelationData) correlationData;
        //获取发送的次数
        int count = correlationData1.getRetryCount();
        //每重发一次，次数加一
        count++;
        //计数之后重新添加进去
        correlationData1.setRetryCount(count);
        redisTemplate.opsForHash().put(RedisConst.RABBIT_PREFIX,correlationData.getId(), JSONObject.toJSONString(correlationData1));

        if(count<=2){
            //当小于规定次数时重发
            rabbitTemplate.convertAndSend(correlationData1.getExchange()
                    ,correlationData1.getRoutingKey(),correlationData1.getMessage(),correlationData1);
            System.out.println("重发完成:"+JSONObject.toJSONString(correlationData1));
        }else {
            //次数已经用完
            System.out.println("剩余发送次数已经用完:"+ JSONObject.toJSONString(correlationData1));
        }
    }

    //队列应答
    //只要失败才会应答
    //message 失败信息体 int i replyCode状态码  s replyText描述信息 s1 exchange交换机名 s2 routingKey路由名
    @Override
    public void returnedMessage(Message message, int i, java.lang.String s, java.lang.String s1, java.lang.String s2) {
        //从消息体中提取消息内容
        System.out.println("message:"+message.getBody().toString());
        System.out.println("replyCode:"+i);
        System.out.println("replyText:"+s);
        System.out.println("exchange:"+s1);
        System.out.println("routingkey:"+s2);
        //从请求头中获取uuid
        String uuid = message.getMessageProperties().getHeader("spring_returned_message_correlation");

        String o = (String) redisTemplate.opsForHash().get(RedisConst.RABBIT_PREFIX, uuid);
        GmallCorrelationData gmallCorrelationData  = JSONObject.parseObject(o, GmallCorrelationData.class);
        //判断是否为插件延迟消息
        if(gmallCorrelationData.getIsDelay()){
            return;
        }
        //重新发送
        rabbitTemplate.convertAndSend(s1,s2,message,gmallCorrelationData);
    }
}
